home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / tuu103d3.zoo / hh / sendbatc / sendbatc.c < prev   
Encoding:
C/C++ Source or Header  |  1992-12-26  |  8.0 KB  |  317 lines

  1. /* sendbatch.c - simple sendbatch for mnews + taylor uucp.
  2.  * pipes the articles thru compress/freeze and into uux directly
  3.  * so that it needs no tempfile.
  4.  * (the original `sbatch' i had doesn't run under MiNT so i needed
  5.  * a new one. :-)
  6.  *
  7.  * send bugs + comments to: Juergen Lock <nox@jelal.north.de>
  8.  *
  9.  */
  10.  
  11. #define SYS_UUX "/usr/local/bin/uux.ttp", "uux", "-rjg", "d", "-", uuxcmd
  12. #define BATCH_DIR "/usr/spool/batch/%s"
  13.  
  14. /* uux command (execl args) to send the batch to. the uuxcmd arg will be
  15.    replaced with system!rnews or system2!rfnews (or frnews) */
  16. #ifndef SYS_UUX
  17. #define SYS_UUX "/usr/local/bin/uux.ttp", "uux", "-rjg", "d", "-", uuxcmd
  18. #endif
  19.  
  20. /* directory where the batch files live, %s is the system name */
  21. #ifndef BATCH_DIR
  22. #define BATCH_DIR "/usr/spool/batch/%s"
  23. #endif
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <fcntl.h>
  29. #include <ctype.h>
  30. #include <stat.h>
  31. #include <process.h>
  32. #include <signal.h>
  33. #include <unistd.h>
  34. #include <errno.h>
  35.  
  36. /* make sure we have EX_TEMPFAIL */
  37. #ifndef EX_TEMPFAIL
  38. #define EX_TEMPFAIL 75
  39. #endif
  40.  
  41. /* write end of the pipe to compress/freeze or (if no compression) uux.
  42.    (global so it can easily be closed on errors.) */
  43. int pfd;
  44.  
  45. /* pid of the exec'd compress or freeze, if any */
  46. int cpid;
  47. /* exit code */
  48. int cret;
  49.  
  50. /* pid of uux */
  51. int upid;
  52. /* and its exit code */
  53. int uret;
  54.  
  55. /* wait for a child.  always check the pid because we usually don't
  56.    know wich one dies first. */
  57. void cwait ()
  58. {
  59.     int status, pid, wait ();
  60.  
  61.     pid = wait (&status);
  62.     if (pid == cpid) {
  63.         cret = status >> 8;
  64.         cpid = 0;
  65.     } else if (pid == upid) {
  66.         uret = status >> 8;
  67.         upid = 0;
  68.     }
  69. }
  70.  
  71. /* print error message, cleanup and exit. */
  72. void fail (ex, msg)
  73. int ex;
  74. char *msg;
  75. {
  76.     void closepipe ();
  77.  
  78.     if (msg)
  79.         fprintf (stderr, "sendbatch: %s\n", msg);
  80.     closepipe (1);
  81.     exit (ex);
  82. }
  83.  
  84. /* close pipe and wait for childs.  if err is 0 check exit codes, else
  85.    return right away because we're called from within the error handler
  86.    already. */
  87. void closepipe (err)
  88. int err;
  89. {
  90.     if (err && upid > 0) {
  91.         /* give processes a chance to die on their own... */
  92.         sleep (1);
  93.         /* else tell uux to forget the current batch. */
  94.         kill (upid, SIGTERM);
  95.     }
  96.     if (pfd) {
  97.         close (pfd);
  98.         pfd = 0;
  99.     }
  100.     if (cpid > 0)
  101.         cwait ();
  102.     if (upid > 0)
  103.         cwait ();
  104.     if (err)
  105.         return;
  106.     if (uret)
  107.         fail (uret, (char *) NULL);
  108.     if (cret)
  109.         fail (cret, "compress or freeze failed");
  110. }
  111.  
  112. /* open a pipe to uux that goes thru ccmd with args in cargs.  if chead
  113.    is != NULL it is sent to uux before ccmd is spawned.  if ccmd is NULL
  114.    the pipe will go to uux without compression.  returns the pipe (fd). */
  115. int openpipe (uuxcmd, ccmd, cargs, chead)
  116. char *uuxcmd;
  117. char *ccmd;
  118. char *cargs;
  119. char *chead;
  120. {
  121.     int upipefd[2], cpipefd[2];
  122.  
  123.     /* first spawn uux... */
  124.     if (pipe (upipefd) < 0 || (upid = fork()) < 0)
  125.         fail (EX_TEMPFAIL, "pipe or fork failed. (not enough memory?)");
  126.  
  127.     if (!upid) {
  128.         /* child */
  129.  
  130.         /* close write end of the pipe */
  131.         close (upipefd[1]);
  132.         /* connect uux' stdin to the pipe */
  133.         if (dup2 (upipefd[0], 0) < 0)
  134.             exit (EX_TEMPFAIL);
  135.         close (upipefd[0]);
  136.         /* ...and exec it. (uuxcmd is used in SYS_UUX) */
  137.         execl (SYS_UUX, (char *) NULL);
  138.         /* exec failed, probably also temporary. */
  139.         perror ("uux");
  140.         exit (EX_TEMPFAIL);
  141.     }
  142.     /* parent */
  143.  
  144.     /* close read end */
  145.     close (upipefd[0]);
  146.  
  147.     if (!ccmd)
  148.         /* no compression, return the pipe to uux. */
  149.         return upipefd[1];
  150.  
  151.     /* if we should write a `#! [cf]unbatch' header do so now */
  152.     if (chead)
  153.         write (upipefd[1], chead, strlen (chead));
  154.  
  155.     /* spawn the compress/freeze */
  156.     if (pipe (cpipefd) < 0 || (cpid = fork()) < 0) {
  157.         /* set pfd so it will get closed */
  158.         pfd = upipefd[1];
  159.         fail (EX_TEMPFAIL, "pipe or fork failed. (not enough memory?)");
  160.     }
  161.  
  162.     if (!cpid) {
  163.         /* child */
  164.  
  165.         /* close write end of the pipe */
  166.         close (cpipefd[1]);
  167.         /* connect stdin and stdout to the pipes */
  168.         if (dup2 (cpipefd[0], 0) < 0 || dup2 (upipefd[1], 1) < 0)
  169.             exit (EX_TEMPFAIL);
  170.         close (cpipefd[0]);
  171.         close (upipefd[1]);
  172.         /* ...and exec. */
  173.         execlp (ccmd, ccmd, cargs, (char *) NULL);
  174.         /* exec failed, probably also temporary. */
  175.         perror (ccmd);
  176.         exit (EX_TEMPFAIL);
  177.     }
  178.     /* parent */
  179.  
  180.     /* close read end */
  181.     close (cpipefd[0]);
  182.     /* close pipe to uux */
  183.     close (upipefd[1]);
  184.  
  185.     /* return pipe to compress/freeze */
  186.     return cpipefd[1];
  187. }
  188.  
  189. /* dummy SIGPIPE handler... */
  190. void dummy (sig)
  191. int sig;
  192. {
  193.     /* do nothing because write will return -1 anyway. */
  194. }
  195.  
  196. int main (argc, argv)
  197. int argc;
  198. char **argv;
  199. {
  200.     static char buf [0x4000];
  201.     char ch, *command = "rnews", uuxcmd[20], cargs[10];
  202.     int rfnews = 0, uncompressed = 0, freeze = 0, verbose = 0, maxbits = 0;
  203.     long maxbatch = 100000, written = 0;
  204.     char fname[FILENAME_MAX], article[FILENAME_MAX];
  205.     FILE *fp;
  206.  
  207.         char *optstr = "ub:rfm:v";
  208.         extern char *optarg;
  209.         extern int optind;
  210.  
  211.     while ((ch = getopt(argc, argv, optstr)) != EOF) {
  212.         switch (ch) {
  213.         case 'u': uncompressed = 1;        break;
  214.         case 'b': if (isdigit(*optarg))
  215.                 maxbits = atoi(optarg);
  216.               break;
  217.         case 'r': if (freeze)
  218.                 command = "frnews";
  219.               else
  220.                 command = "rfnews";
  221.               rfnews     = 1;        break;
  222.         case 'f': freeze     = 1;        break;
  223.         case 'm': if (isdigit(*optarg))
  224.                 maxbatch = 0x400 * atoi(optarg);
  225.               break;
  226.         case 'v': ++verbose;            break;
  227.         default:  goto usage;
  228.         }
  229.     }
  230.     if (argc <= optind || argc > optind + 1 ||
  231.         (freeze && uncompressed) || (rfnews && !freeze)) {
  232. usage:
  233.         fprintf (stderr,
  234.             "usage: sendbatch [-u|-f|-rf|-fr] [-b maxbits] [-m maxkperbatch] [-v] site\n\n"
  235.             "-u:    send uncompressed batch\n"
  236.             "-f:    use freeze instead of compress\n"
  237.             "-rf:    ditto but send to rfnews and without a `#! funbatch' header\n"
  238.             "-fr:    same but frnews instead or rfnews\n"
  239.             "-b:    -b arg to compress (default = none, use compress' default)\n"
  240.             "-m:    maximum size (Kbytes) of a single batch before compression,\n"
  241.             "    more data will be split into multiple batches as long as no\n"
  242.             "    single article is longer. (default = 100)\n"
  243.             "-v    verbose (not yet.)\n");
  244.         exit (1);
  245.     }
  246.  
  247.     sprintf (uuxcmd, "%s!%s", argv[optind], command);
  248.     if (maxbits)
  249.         sprintf (cargs, "-b%d", maxbits);
  250.  
  251.     /* try open the batch file */
  252.     sprintf (fname, BATCH_DIR, argv[optind]);
  253.  
  254.     if (!(fp = fopen (fname, "r"))) {
  255.         /* if its just not there then we're finished */
  256.         if (errno == ENOENT)
  257.             exit (0);
  258.         perror (fname);
  259.         exit (1);
  260.     }
  261.  
  262.     /* catch and ignore SIGPIPE. (we check the result of the write()
  263.        calls so ignoring is ok.)  can't use SIG_IGN because then our
  264.        childs would ignore SIGPIPE also... */
  265.     signal (SIGPIPE, dummy);
  266.  
  267.     /* read thru the file, open each article and send it down the pipe */
  268.     while (fgets (article, sizeof article, fp)) {
  269.         char line[30], *p;
  270.         int count, fd;
  271.         struct stat st;
  272.  
  273.         if (*(p = article + strlen (article) - 1) == '\n')
  274.           *p = 0;
  275.         if ((fd = open (article, O_RDONLY)) < 0 || fstat (fd, &st) < 0)
  276.             fail (1, strerror (errno));
  277.  
  278.         /* make sure it wouldn't make the current batch too large */
  279.         if (pfd && written + st.st_size + sizeof "#! rnews 1234567890\n" > maxbatch) {
  280.             closepipe (0);
  281.             written = 0;
  282.         }
  283.  
  284.         /* open the next batch if necessary */
  285.         if (!pfd)
  286.             pfd = openpipe (uuxcmd, uncompressed ? (char *) NULL :
  287.                      (freeze ? "freeze" : "compress"),
  288.                     maxbits ? cargs : (char *) NULL,
  289.                     (rfnews || uncompressed) ? (char *) NULL :
  290.                      (freeze ? "#! funbatch\n" : "#! cunbatch\n"));
  291.  
  292.         /* write the #! rnews... */
  293.         sprintf (line, "#! rnews %ld\n", st.st_size);
  294.         write (pfd, line, count = strlen (line));
  295.         written += count;
  296.  
  297.         /* ...and copy the article. */
  298.         while ((count = read (fd, buf, sizeof buf)) > 0) {
  299.             if (write (pfd, buf, count) != count) {
  300.                 close (fd);
  301.                 fail (1, strerror (errno));
  302.             }
  303.             written += count;
  304.         }
  305.         if (close (fd) < 0 || count < 0)
  306.             fail (1, strerror (errno));
  307.     }
  308.  
  309.     if (ferror (fp) || fclose (fp))
  310.         fail (1, strerror (errno));
  311.     if (pfd)
  312.         closepipe (0);
  313.  
  314.     unlink (fname);
  315.     exit (0);
  316. }
  317.